#include "Signal.h"
#include "LengthField.h"
#include <cstdint>

Signal::Signal(size_t inChannels, size_t inElements)
	:mNumChannels(inChannels),
	mNumElements(inElements),
	mpValue(NULL)
{
	if(mNumChannels == 0 || mNumElements == 0)
		mpValue = NULL;
	else
	{
		mpValue = new ValueType[mNumChannels * mNumElements];
		::memset(mpValue, 0, sizeof(ValueType)*(mNumChannels*mNumElements));
	}
}

Signal::~Signal()
{
	if(mpValue)
		delete[] mpValue;
}

void Signal::InitSignal(size_t inChannel, size_t inElement)
{
	mNumChannels = inChannel;
	mNumElements = inElement;
	if(mpValue)
		delete[] mpValue;
	mpValue = NULL;
	mpValue = new ValueType[mNumChannels * mNumElements];
	::memset(mpValue, 0, sizeof(ValueType)*(mNumChannels*mNumElements));
}

std::ostream& Signal::WriteBinary(std::ostream& os) const
{
	LengthField<2> channelsField(mNumChannels),
		elementsField(mNumElements);
	channelsField.WriteBinary(os);
	elementsField.WriteBinary(os);
	union{float f; uint32_t i;} value;
	for(int i=0; i<mNumChannels; ++i)
	{
		for(int j=0; j<mNumElements; ++j)
		{
			value.f = static_cast<float>((*this)(i,j));
			PutLittleEndian(os, value.i);
		}
	}

	return os;
}

std::istream& Signal::ReadBinary(std::istream& is)
{
	LengthField<2> channelsField,
		elementsField;
	channelsField.ReadBinary(is);
	elementsField.ReadBinary(is);
	InitSignal(channelsField,elementsField);
	union{float f; uint32_t i;} value;
	for(int i=0; i<mNumChannels; ++i)
	{
		for(int j=0; j<mNumElements; ++j)
		{
			GetLittleEndian(is, value.i);
			SetValue(i,j, value.f);
		}
	}

	return is;
}

template<typename T>
void Signal::PutLittleEndian( std::ostream& os, const T& inValue )
{
	T value = inValue;
	for( size_t i = 0; i < sizeof( T ); ++i )
	{
		os.put( value & 0xff );
		value >>= 8;
	}
}

template<typename T>
void Signal::GetLittleEndian( std::istream& is, T& outValue )
{
	outValue = 0;
	for( size_t i = 0; i < sizeof( T ); ++i )
		outValue |= is.get() << ( i * 8 );
}